from flask import current_app
from wtforms.validators import ValidationError
import re
from .models import db, User

class Unique:
    """
    验证字段值在数据库中是否唯一
    """
    def __init__(self, model, field, message=None):
        self.model = model
        self.field = field
        self.message = message or '该值已存在'

    def __call__(self, form, field):
        # 查询数据库中是否存在该值
        if self.model.query.filter(self.field == field.data).first():
            raise ValidationError(self.message)

class EmailValidator:
    """
    增强的邮箱格式验证器
    """
    def __init__(self, message=None):
        self.message = message or '无效的邮箱地址'
        # 更严格的邮箱正则表达式
        self.regex = re.compile(
            r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        )

    def __call__(self, form, field):
        email = field.data
        if not self.regex.match(email):
            raise ValidationError(self.message)
        
        # 检查邮箱域名是否存在（可选，生产环境建议启用）
        if current_app.config.get('VERIFY_EMAIL_DOMAIN', False):
            domain = email.split('@')[-1]
            try:
                import socket
                socket.getaddrinfo(domain, None)
            except socket.gaierror:
                raise ValidationError('邮箱域名不存在')

class StrongPassword:
    """
    密码强度验证器
    要求密码包含：
    - 至少8个字符
    - 至少1个大写字母
    - 至少1个小写字母
    - 至少1个数字
    - 至少1个特殊字符
    """
    def __init__(self, message=None):
        self.message = message or (
            '密码必须包含至少8个字符，包括大写字母、小写字母、数字和特殊字符'
        )

    def __call__(self, form, field):
        password = field.data
        
        # 检查长度
        if len(password) < 8:
            raise ValidationError(self.message)
        
        # 检查是否包含大写字母
        if not re.search(r'[A-Z]', password):
            raise ValidationError(self.message)
        
        # 检查是否包含小写字母
        if not re.search(r'[a-z]', password):
            raise ValidationError(self.message)
        
        # 检查是否包含数字
        if not re.search(r'[0-9]', password):
            raise ValidationError(self.message)
        
        # 检查是否包含特殊字符
        if not re.search(r'[!@#$%^&*()_+=\-[\]{};:\'"|,.<>?/~`]', password):
            raise ValidationError(self.message)

class PasswordHistory:
    """
    密码历史验证器
    确保新密码不在用户的最近N个历史密码中
    """
    def __init__(self, history_count=3, message=None):
        self.history_count = history_count
        self.message = message or '不能使用最近使用过的密码'

    def __call__(self, form, field):
        # 实际实现需要密码历史表支持
        # 这里仅提供概念验证
        if form.user_id:  # 假设表单中有用户ID
            user = User.query.get(form.user_id)
            # 检查新密码是否与当前密码相同
            if user.check_password(field.data):
                raise ValidationError(self.message)
            # 实际应用中应查询密码历史表

class UsernameValidator:
    """
    用户名格式验证器
    """
    def __init__(self, message=None):
        self.message = message or (
            '用户名只能包含字母、数字和下划线，长度3-20个字符'
        )
        self.regex = re.compile(r'^[a-zA-Z0-9_]{3,20}$')

    def __call__(self, form, field):
        username = field.data
        if not self.regex.match(username):
            raise ValidationError(self.message)
        
        # 检查保留用户名
        reserved_names = ['admin', 'root', 'system', 'administrator']
        if username.lower() in reserved_names:
            raise ValidationError('该用户名是保留名称，不能使用')

class CaptchaValidator:
    """
    验证码验证器（需要与前端集成）
    """
    def __init__(self, message=None):
        self.message = message or '验证码错误'

    def __call__(self, form, field):
        # 实际实现需要与验证码服务集成
        captcha = field.data
        session_captcha = form.session_captcha  # 假设表单中有session_captcha
        
        # 简单比较，实际应用应使用常量时间比较
        if captcha.lower() != session_captcha.lower():
            raise ValidationError(self.message)

class PasswordConfirmation:
    """
    确认密码匹配验证器
    """
    def __init__(self, confirm_field='confirm', message=None):
        self.confirm_field = confirm_field
        self.message = message or '两次输入的密码不一致'

    def __call__(self, form, field):
        confirm = getattr(form, self.confirm_field).data
        if field.data != confirm:
            raise ValidationError(self.message)

class NoSQLInjection:
    """
    防止SQL注入的简单验证器
    """
    def __init__(self, message=None):
        self.message = message or '输入包含非法字符'
        # 常见SQL注入关键词
        self.forbidden_patterns = [
            r'\b(select|union|insert|update|delete|drop|alter|create|exec|xp_cmdshell)\b',
            r'[\'";]',
            r'--',
            r'/\*.*\*/'
        ]

    def __call__(self, form, field):
        value = field.data
        for pattern in self.forbidden_patterns:
            if re.search(pattern, value, re.IGNORECASE):
                raise ValidationError(self.message)

class NoXSS:
    """
    XSS攻击预防验证器
    """
    def __init__(self, message=None):
        self.message = message or '输入包含不安全内容'
        # XSS常见模式
        self.forbidden_patterns = [
            r'<script.*?>.*?</script>',
            r'on\w+\s*=',
            r'javascript:',
            r'<\s*iframe',
            r'<\s*img\s+.*?src\s*='
        ]

    def __call__(self, form, field):
        value = field.data
        for pattern in self.forbidden_patterns:
            if re.search(pattern, value, re.IGNORECASE):
                raise ValidationError(self.message)